﻿using System;
using System.Collections.Generic;
using PhiStore.Policies;
using PhiStore.ReturnCodes;

namespace PhiStore.ExampleCodes.PhiLog
{
    public class PhiLog
    {
        private const string LogPrefix = "phi_log_";

        private PhiClient<LogEntry> client;
        private Policy policy;

        private HashSet<string> logDates;

        public PhiLog(uint replications, bool encryptConnection, bool compressObjects, bool encryptObjects, bool use2PC)
        {

            logDates = new HashSet<string>();

            client = new PhiClient<LogEntry>(encryptConnection, false);
            client.Initialize(compressObjects, encryptObjects ? "Hello" : "");
            client.Connect();

            policy = new Policy();
            policy.ReplicationNumber = replications;
            policy.EnforceAtomicity = use2PC;
            policy.FastReturn = false;
            policy.MayGarbageCollect = false;
            policy.IdleThreshold = 24 * 60 * 60 * 1000; //24h
            policy.MayAppend = true; //<-- Append only
            policy.MayDelete = false;
            policy.MayPop = false;
            policy.MayModify = false;
        }

        private bool DateLogExist(string Date)
        {
            if (logDates.Contains(Date))
            {
                return true;
            }

            try
            {
                client.ListCount(LogPrefix + Date);
                logDates.Add(Date);
                return true;
            }
            catch (PhiException)
            {
                return false;
            }
        }

        //add object for today iff not exist
        private string createEmptyDateLog()
        {
            string Date = DateTime.Now.ToShortDateString();
            if (!DateLogExist(Date))
            {
                try
                {
                    client.ListCreate(LogPrefix + Date, new List<LogEntry>(), policy);
                }
                catch (PhiException)
                {
                    //simultaneous add from somewhere else
                }
                logDates.Add(Date);
            }
            return LogPrefix + Date;
        }

        /// <summary>
        /// Adds a log entry to the remote client
        /// </summary>
        /// <param name="Identifier">Unique identifier for logging party</param>
        /// <param name="LogMessage">Message to be logged</param>
        /// <returns>addition success/failure</returns>
        public bool addLogEntry(string Identifier, string LogMessage)
        {
            return addLogEntry(new LogEntry(Identifier, LogMessage));
        }

        /// <summary>
        /// Adds a log entry to the remote client
        /// </summary>
        /// <param name="entry">The entry to add</param>
        /// <returns>addition success/failure</returns>
        public bool addLogEntry(LogEntry entry)
        {
            string key = createEmptyDateLog();
            try
            {
                client.ListAppend(key, entry);
                return true;
            }
            catch (PhiException)
            {
                return false; //not added
            }
        }

        public void Stop()
        {
            client.Disconnect();
        }
    }
}
